using System;
using System.Linq;
using System.Linq.Expressions;
using Magiq.Tests.Support;
using Magiq.Tests.TestModel;
using NUnit.Framework;

namespace Magiq.Tests {
    public abstract class BaseMagiqProviderDeletesTest<TTestClass> : BaseMagiqProviderTest<TTestClass>
        where TTestClass : class, ITestClass<TTestClass>, new()
    {
        [Test]
        public void ShouldDeleteAll() {
            var count = TestClassInstances.Count();
            TestClassInstances.Delete().Should(Be.EqualTo(count));
            TestClassInstances.Count().Should(Be.EqualTo(0));
        }

        [Test]
        public void ShouldDeleteWhereThatUsesStringProperty() {
            TestDelete(TestClassInstances, x => x.StringProperty == "sarasa");
        }

        [Test]
        public void ShouldDeleteWhereThatUsesAnotherStringProperty() {
            TestDelete(TestClassInstances, x => x.StringProperty == x.AnotherStringProperty);
        }

        [Test]
        public void ShouldDeleteComplexWhere() {
            TestDelete(TestClassInstances, x => (x.StringProperty == "sarasa" && x.IntProperty >= 3) ||
                                          x.AnotherIntProperty < 12 &&
                                          x.AnotherStringProperty != null);
        }

        [Test]
        public void ShouldDeleteWhereThatUsesSelfReference() {
            TestDelete(TestClassInstances, x => x.SelfReference != null && x.SelfReference.IntProperty > 3);
        }

        [Test]
        public void ShouldDeleteWhereThatUsesStringPropertyNull() {
            TestDelete(TestClassInstances, x => x.StringProperty == null);
        }

        [Test]
        public void ShouldDeleteWhereThatUsesComposedStringProperty() {
            TestDelete(TestClassInstances, x => x.StringProperty == x.AnotherStringProperty + "la");
        }

        [Test]
        public void ShouldDeleteWhereThatUsesIntProperty() {
            var items = TestClassInstances.Where(x => x.IntProperty == 3);
            var count = items.Count();
            items.Delete().Should(Be.EqualTo(count));
        }

        [Test]
        public void ShouldDeleteWhereThatUsesComposedIntProperty() {
            var items = TestClassInstances.Where(x => x.IntProperty == x.AnotherIntProperty + 3);
            var count = items.Count();
            items.Delete().Should(Be.EqualTo(count));
        }

        [Test]
        public void ShouldDeleteWhereThatUsesAnotherIntProperty() {
            var items = TestClassInstances.Where(x => x.IntProperty == x.AnotherIntProperty);
            var count = items.Count();
            items.Delete().Should(Be.EqualTo(count));
        }

        [Test]
        public void ShouldDeleteWhereThatUsesReferenceIds()
        {
            var r = ReferenceClassInstances.First();
            var items = TestClassInstances.Where(x => x.Reference != null && x.Reference.Id == r.Id);
            var count = items.Count();
            items.Delete().Should(Be.EqualTo(count));
        }

        [Test]
        public void ShouldDeleteWhereThatUsesReferenceNull() {
            var items = TestClassInstances.Where(x => x.Reference == null);
            var count = items.Count();
            items.Delete().Should(Be.EqualTo(count));
        }

        [Test]
        public void ShouldDeleteWhereThatUsesNullableIntProperty() {
            var items = TestClassInstances.Where(x => x.NullableIntProperty == 3);
            var count = items.Count();
            items.Delete().Should(Be.EqualTo(count));
        }

        [Test]
        public void ShouldDeleteWhereThatUsesNullableIntPropertyNull() {
            var items = TestClassInstances.Where(x => x.NullableIntProperty == null);
            var count = items.Count();
            items.Delete().Should(Be.EqualTo(count));
        }

        [Test]
        public void ShouldDeleteWhereThatUsesNullableIntPropertyWithIntProperty() {
            var items = TestClassInstances.Where(x => x.NullableIntProperty == x.IntProperty);
            var count = items.Count();
            items.Delete().Should(Be.EqualTo(count));
        }


        [Test]
        public void ShouldDeleteWhereThatUsesNullableIntPropertyToNull() {
            var items = TestClassInstances.Where(x => x.NullableIntProperty == null);
            var count = items.Count();
            items.Delete().Should(Be.EqualTo(count));
        }

        private static void TestDelete<T>(IQueryable<T> queryable, Expression<Func<T, bool>> where) where T : class {
            var items = queryable.Where(where);
            var count = items.Count();
            queryable.Where(where).Delete().Should(Be.EqualTo(count));
            queryable.Where(where.Compile()).Count().Should(Be.EqualTo(0));
        }
        }
}